package avicit.bdp.dds.api.controller;

import avicit.bdp.common.api.TaskAPI;
import avicit.bdp.common.dto.EnumDto;
import avicit.bdp.dds.dispatch.enums.ExecutionStatus;
import avicit.bdp.dds.api.enums.Status;
import avicit.bdp.dds.api.service.ProcessInstanceService;
import avicit.bdp.dds.common.Constants;
import avicit.bdp.dds.common.utils.ParameterUtils;
import avicit.bdp.dds.dao.entity.ProcessInstance;
import avicit.bdp.dds.dao.entity.TaskInstance;
import avicit.platform6.core.rest.msg.QueryRespBean;
import avicit.platform6.core.rest.msg.ResponseMsg;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 流程实例REST接口
 */
@RestController
@Api(tags = "流程实例REST接口")
@RequestMapping("/api/bdp/dds/instance")
public class ProcessInstanceRest {

	private static final Logger logger = LoggerFactory.getLogger(ProcessInstanceRest.class);

	@Autowired
	private ProcessInstanceService processInstanceService;
	@Autowired
	private TaskAPI taskAPI;
	@Value("${dcsAPI.url}")
	private String dcsAPIUrl;

	/**
	 * query process instance list paging
	 *
	 * 分页查询流程实例列表
	 */
	@ApiOperation(value = "分页查询流程实例列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "processDefinitionId", value = "流程定义id", dataType = "String"),
			@ApiImplicitParam(name = "searchVal", value = "关键字", type = "String"),
			@ApiImplicitParam(name = "stateType", value = "任务状态", type = "ExecutionStatus"),
			@ApiImplicitParam(name = "host", value = "HOST", type = "String"),
			@ApiImplicitParam(name = "startDate", value = "开始时间", type = "String"),
			@ApiImplicitParam(name = "endDate", value = "结束时间", type = "String"),
			@ApiImplicitParam(name = "pageNo", value = "当前页", dataType = "Int"),
			@ApiImplicitParam(name = "pageSize", value = "每页大小", dataType = "Int")
	})
	@GetMapping(value = "list-paging")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<QueryRespBean<ProcessInstance>> queryProcessInstanceList(
			@RequestParam(value = "processDefinitionId", required = false, defaultValue = "0") String processDefinitionId,
			@RequestParam(value = "searchVal", required = false) String searchVal,
			@RequestParam(value = "stateType", required = false) ExecutionStatus stateType,
			@RequestParam(value = "host", required = false) String host,
			@RequestParam(value = "startDate", required = false) String startTime,
			@RequestParam(value = "endDate", required = false) String endTime,
			@RequestParam("pageNo") Integer pageNo,
			@RequestParam("pageSize") Integer pageSize) {

		ResponseMsg<QueryRespBean<ProcessInstance>> responseMsg = new ResponseMsg<>();

		logger.info("query all process instance list,define id:{},search value:{},state type:{},host:{}," +
						"start time:{}, end time:{},page number:{}, page size:{}",
				processDefinitionId, searchVal, stateType, host, startTime, endTime, pageNo, pageSize);

		searchVal = ParameterUtils.handleEscapes(searchVal);

		QueryRespBean<ProcessInstance> result = processInstanceService.queryProcessInstanceList(processDefinitionId,
				startTime, endTime, searchVal, stateType, host, pageNo, pageSize);
		responseMsg.setResponseBody(result);

		return responseMsg;
	}

	/**
	 * query task list by process instance id
	 *
	 * @param processInstanceId process instance id
	 * @return task list for the process instance
	 */
	@ApiOperation(value = "根据流程实例id查询任务节点列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "processInstanceId", value = "流程实例id", dataType = "String", required = true)
	})
	@GetMapping(value = "/task-list-by-process-id")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<List<TaskInstance>> queryTaskListByProcessId(@RequestParam("processInstanceId") String processInstanceId)
			throws IOException {

		logger.info("query task instance list by process instance id, process instance id:{}", processInstanceId);

		ResponseMsg<List<TaskInstance>> responseMsg = new ResponseMsg<>();

		List<TaskInstance> taskInstances = processInstanceService.queryTaskListByProcessId(processInstanceId);
		responseMsg.setResponseBody(taskInstances);
		return responseMsg;
	}

	/**
	 * 修改流程实例对象
	 */
	@ApiOperation(value = "修改流程实例对象")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "projectName", value = "空间名称", dataType = "String",paramType = "path",required = true),
			@ApiImplicitParam(name = "processInstanceJson", value = "流程定义json", type = "String"),
			@ApiImplicitParam(name = "processInstanceId", value = "流程实例ID", dataType = "String", required = true),
			@ApiImplicitParam(name = "scheduleTime", value = "调度时间", dataType = "String"),
			@ApiImplicitParam(name = "syncDefine", value = "SYNC_DEFINE", dataType = "Boolean", required = true),
			@ApiImplicitParam(name = "locations", value = "节点位置json", dataType = "String"),
			@ApiImplicitParam(name = "connects", value = "节点连接json", dataType = "String"),
	})
	@PostMapping(value = "/update")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg updateProcessInstance(@PathVariable String projectName,
											 @RequestParam(value = "processInstanceJson", required = false) String processInstanceJson,
											 @RequestParam(value = "processInstanceId") String processInstanceId,
											 @RequestParam(value = "scheduleTime", required = false) String scheduleTime,
											 @RequestParam(value = "syncDefine") Boolean syncDefine,
											 @RequestParam(value = "locations", required = false) String locations,
											 @RequestParam(value = "connects", required = false) String connects
	) throws ParseException {

		ResponseMsg responseMsg = new ResponseMsg<>();

		logger.info("updateProcessInstance process instance, login user:{}, project name:{}, process instance json:{}," +
						"process instance id:{}, schedule time:{}, sync define:{}, flag:{}, locations:{}, connects:{}",
				"", projectName, processInstanceJson, processInstanceId, scheduleTime,
				syncDefine, "", locations, connects);

		processInstanceService.updateProcessInstance(processInstanceId, processInstanceJson,
				scheduleTime, syncDefine, locations, connects);

		return responseMsg;
	}

	/**
	 * 根据id查询流程实例
	 */
	@ApiOperation(value = "根据id查询流程实例")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "processInstanceId", value = "流程实例ID", dataType = "String"),
			@ApiImplicitParam(name = "processDefinitionId", value = "流程定义id", dataType = "String")
	})
	@GetMapping(value = "/select-by-id")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<ProcessInstance> queryProcessInstanceById(@RequestParam(value = "processDefinitionId", required = false) String processDefinitionId,
																 @RequestParam(value = "processInstanceId", required = false) String processInstanceId) {

		logger.info("query process instance detail by id, login user:{},project name:{}, process instance id:{}",
				"", "", processInstanceId);

		ResponseMsg<ProcessInstance> responseMsg = new ResponseMsg<>();
		ProcessInstance processInstance = processInstanceService.queryProcessInstanceById(processDefinitionId, processInstanceId);
		responseMsg.setResponseBody(processInstance);
		return responseMsg;
	}

	/**
	 * 根据id删除流程实例
	 */
	@ApiOperation(value = "根据id删除流程实例")
	@ApiImplicitParam(name = "processInstanceId", value = "流程实例ID", dataType = "String", required = true)
	@GetMapping(value = "/delete")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg deleteProcessInstanceById(@RequestParam("processInstanceId") String processInstanceId) {

		logger.info("delete process instance by id, login user:{}, project name:{}, process instance id:{}",
				"", "", processInstanceId);
		// task queue
		ResponseMsg responseMsg = new ResponseMsg<>();

		processInstanceService.deleteProcessInstanceById(processInstanceId);

		return responseMsg;
	}

	/**
	 * 根据任务id查询子流程实例
	 */
	@ApiOperation(value = "根据任务id查询子流程实例")
	@ApiImplicitParam(name = "taskId", value = "任务id", dataType = "String", required = true)
	@GetMapping(value = "/select-sub-process")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<String> querySubProcessInstanceByTaskId(@RequestParam("taskId") String taskId) {
		ResponseMsg<String> responseMsg = new ResponseMsg<>();
		String result = processInstanceService.querySubProcessInstanceByTaskId(taskId);
		responseMsg.setResponseBody(result);
		return responseMsg;
	}

	/**
	 * 根据流程实例id查询上一级流程实例
	 */
	@ApiOperation(value = "根据流程实例id查询上一级流程实例")
	@ApiImplicitParam(name = "subId", value = "流程实例id", dataType = "String", required = true)
	@GetMapping(value = "/select-parent-process")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<String> queryParentInstanceBySubId(@RequestParam("subId") String subId) {
		ResponseMsg<String> responseMsg = new ResponseMsg<>();
		String result = processInstanceService.queryParentInstanceBySubId(subId);
		responseMsg.setResponseBody(result);
		return responseMsg;
	}

	/**
	 * 查询流程实例全局变量和局部变量
	 *
	 * @param processInstanceId process instance id
	 * @return variables data
	 */
	@ApiOperation(value = "查询流程实例全局变量和局部变量")
	@ApiImplicitParam(name = "processInstanceId", value = "流程实例id", dataType = "String", required = true)
	@GetMapping(value = "/view-variables")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg<Map<String, Object>> viewVariables(@RequestParam("processInstanceId") String processInstanceId) throws Exception {
		ResponseMsg<Map<String, Object>> responseMsg = new ResponseMsg<>();
		Map<String, Object> result = processInstanceService.viewVariables(processInstanceId);
		responseMsg.setResponseBody(result);
		return responseMsg;
	}

	/**
	 * 根据流程实例id集合批量删除
	 */
	@ApiOperation(value = "根据流程实例id集合批量删除")
	@ApiImplicitParam(name = "processInstanceIds", value = "流程实例id集合，逗号分隔", dataType = "String")
	@GetMapping(value = "/batch-delete")
	@ResponseStatus(HttpStatus.OK)
	public ResponseMsg batchDeleteProcessInstanceByIds(@RequestParam("processInstanceIds") String processInstanceIds) {
		ResponseMsg<Map<String, Object>> responseMsg = new ResponseMsg<>();
		logger.info("delete process instance by ids, login user:{}, project name:{}, process instance ids :{}",
				"", "", processInstanceIds);
		// task queue
		List<String> deleteFailedIdList = new ArrayList<>();
		if (StringUtils.isNotEmpty(processInstanceIds)) {
			String[] processInstanceIdArray = processInstanceIds.split(Constants.COMMA);

			for (String processInstanceId : processInstanceIdArray) {
				try {
					boolean deleteResult = processInstanceService.deleteProcessInstanceById(processInstanceId);
					if (!deleteResult) {
						deleteFailedIdList.add(processInstanceId);
					}
				} catch (Exception e) {
					deleteFailedIdList.add(processInstanceId);
					logger.error(e.getMessage());
				}
			}
		}
		if (!deleteFailedIdList.isEmpty()) {
			throw new RuntimeException(MessageFormat.format(Status.BATCH_DELETE_PROCESS_INSTANCE_BY_IDS_ERROR.getMsg(),
					String.join(Constants.COMMA, deleteFailedIdList)));
		}
		return responseMsg;
	}


    /**
     * 获取监控列表
     */
	@ApiOperation(value = "获取监控列表")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "projectId", value = "数据空间id", type = "String"),
			@ApiImplicitParam(name = "processDefinitionId", value = "流程定义id", type = "String"),
			@ApiImplicitParam(name = "instanceName", value = "任务名称", type = "String"),
			@ApiImplicitParam(name = "startTime", value = "开始时间", type = "String"),
			@ApiImplicitParam(name = "endTime", value = "结束时间", type = "String"),
			@ApiImplicitParam(name = "instanceStatus", value = "任务状态", type = "Int"),
			@ApiImplicitParam(name = "type", value = "任务类型", type = "Int"),
			@ApiImplicitParam(name = "pageNo", value = "当前页", type = "Int"),
			@ApiImplicitParam(name = "pageSize", value = "每页大小", type = "Int")
	})
    @GetMapping("/getListForControl")
    public ResponseMsg<QueryRespBean<ProcessInstance>> getListForControl(@RequestParam(required = false) String projectId,
                                                                         @RequestParam(required = false) String definitionId,
                                                                         @RequestParam(required = false) String instanceName,
                                                                         @RequestParam(required = false) String startTime,
                                                                         @RequestParam(required = false) String endTime,
                                                                         @RequestParam(required = false) Integer instanceStatus,
                                                                         @RequestParam(required = false) Integer type,
                                                                         @RequestParam(defaultValue = "1", required = false) Integer pageNo,
                                                                         @RequestParam(defaultValue = "10", required = false) Integer pageSize) {
        ResponseMsg<QueryRespBean<ProcessInstance>> responseMsg = new ResponseMsg<>();
        QueryRespBean<ProcessInstance> result = processInstanceService.getListForControl(projectId, definitionId,
                instanceName, startTime, endTime, instanceStatus,type,
                pageNo, pageSize);
        if (result.getResult() != null) {
            responseMsg.setResponseBody(result);
        } else {
            responseMsg.setResponseBody(null);
        }
        return responseMsg;
    }

	/**
	 * 获取状态列表
	 */
	@GetMapping("/getStateList")
	@ApiOperation(value = "获取状态列表")
	public ResponseMsg<List<EnumDto>> getStateList() {
		ResponseMsg<List<EnumDto>> responseMsg = new ResponseMsg<>();
		List<EnumDto> result = processInstanceService.getStateList();
		responseMsg.setResponseBody(result);
		return responseMsg;
	}


	/**
	 * 获取子任务流程实例
	 */
	@ApiOperation(value = "获取子任务流程实例")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "taskInstanceId", value = "流程节点ID", type = "String"),
			@ApiImplicitParam(name = "processInstanceId", value = "流程实例ID", type = "String")
	})
	@GetMapping("/getSubInstance")
	public ProcessInstance getSubInstance(
			@RequestParam String taskInstanceId,
			@RequestParam String processInstanceId) {

		return processInstanceService.getSubInstance(taskInstanceId, processInstanceId);
	}


	@ApiOperation(value = "创建表")
	@ApiImplicitParam(name = "taskId", value = "任务id", dataType = "String",paramType = "path")
	@GetMapping("/createTable/{taskId}")
	public ResponseMsg<Boolean> createTable(@PathVariable String taskId) throws Exception {
		ResponseMsg<Boolean> responseMsg = new ResponseMsg<>();
		boolean flag = taskAPI.createTable(dcsAPIUrl, taskId);
		responseMsg.setResponseBody(flag);
		return responseMsg;
	}

	@ApiOperation(value = "获取待同步的文件")
	@ApiImplicitParam(name = "taskId", value = "任务id", dataType = "String",paramType = "path")
	@GetMapping("/getSyncFile/{taskId}")
	public ResponseMsg<String> getSyncFile(@PathVariable String taskId) throws Exception {
		ResponseMsg<String> responseMsg = new ResponseMsg<>();
		responseMsg.setResponseBody(taskAPI.getSyncFile(dcsAPIUrl, taskId));
		return responseMsg;
	}

	@ApiOperation(value = "前置处理")
	@ApiImplicitParam(name = "taskId", value = "任务id", dataType = "String",paramType = "path")
	@GetMapping("/preProcess/{taskId}")
	public ResponseMsg<Boolean> preProcess(@PathVariable String taskId) throws Exception {
		ResponseMsg<Boolean> responseMsg = new ResponseMsg<>();
		boolean flag = taskAPI.preProcess(dcsAPIUrl, taskId);
		responseMsg.setResponseBody(flag);
		return responseMsg;
	}

}
